// 引入进度条
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'

import { ElMessage } from 'element-plus'
import 'element-plus/es/components/message/style/css'

import i18n from '@/i18n'
import defaultSettings from '@/settings'
import getPageTitle from '@/utils/getPageTitle'
import { getToken } from '@/utils/auth'
import useStore from '@/stores'

import { NavigationFailureType } from 'vue-router'

/**
 * 处理导航失败
 *
 * 当 Vue Router 在导航过程中遇到错误时，此函数会被调用。
 * 它会根据错误类型进行不同的处理，并记录相关信息。
 *
 * @param {RouteLocationNormalizedLoaded} to - 目标路由对象
 * @param {RouteLocationNormalizedLoaded} from - 当前路由对象
 * @param {NavigationFailure} failure - 导航失败的对象，包含失败类型和相关信息
 */
function handleNavigationFailure(to, from, failure) {
    switch (failure.type) {
        case NavigationFailureType.aborted:
            // 用户取消了导航
            console.error('Navigation was aborted:', failure)
            sendToAnalytics(to, from, failure)
            break
        case NavigationFailureType.duplicated:
            // 用户重复导航到同一位置
            console.error('Navigation was duplicated:', failure)
            sendToAnalytics(to, from, failure)
            break
        case NavigationFailureType.cancelled:
            //在当前导航完成之前又有了一个新的导航
            console.error('Navigation was cancelled:', failure)
            sendToAnalytics(to, from, failure)
            break
        default:
            // 其他未知错误
            console.error('Unknown navigation failure:', failure)
            sendToAnalytics(to, from, failure)
    }
}
/**
 * 发送到分析工具
 *
 * 此函数用于记录用户的导航行为，并在导航失败时记录失败信息。
 * 它会记录从哪个路由导航到哪个路由，并附加导航失败的详细信息（如果有的话）。
 *
 * @param {RouteLocationNormalizedLoaded} to - 目标路由对象
 * @param {RouteLocationNormalizedLoaded} from - 当前路由对象
 * @param {NavigationFailure|null} [failure=null] - 导航失败的对象（如果导航失败的话）
 */
function sendToAnalytics(to, from, failure = null) {
    // 记录导航完成的信息
    console.log(`Navigated from ${from.path} to ${to.path}`)
    if (failure) {
        console.error(`Navigation failure: ${failure.type}`, failure)
    }
}
/**
 * 处理进度条的启动和结束,否则通过redirect组件跳转会也会展示进度条
 *
 * @param {RouteLocationNormalizedLoaded} to - 目标路由对象
 * @param {Boolean} isStart - 是否是启动进度条
 */
function handleNProgress(to, isStart) {
    // 显示右上角螺旋加载提示
    NProgress.configure({
        showSpinner: false
    })
    const isRedirectPath = /^\/redirect/.test(to.path)
    if (!isRedirectPath) {
        if (isStart) {
            NProgress.start()
        } else {
            NProgress.done()
        }
    }
}
/**
 * 角色和权限处理函数
 */
async function rolesAndPermissionsHandler(router, to, from, next) {
    const { user, permission } = useStore()
    try {
        const { roles, permissions } = await user.GetInfo()
        // 根据用户权限生成路由
        const accessRoutes = await permission.generateRoutes(roles, permissions)
        // 动态添加路由
        accessRoutes.forEach((_route) => {
            router.addRoute(_route)
        })
        //路由匹配在动态路由添加前已经完成匹配,导致to.mached 匹配动态路由地址是空的,需要处理后再放行
        next({ ...to, replace: true })
    } catch (err) {
        // 处理错误，例如用户未登录或权限不足
        await user.LogOut()
        ElMessage.error(
            (err.response && err.response.data && err.response.data.msg) ||
                err.message ||
                '登录状态异常，请重新登录'
        )
        next({ path: '/' })
    }
}
export default function setupGuards(router) {
    //全局前置路由守卫————初始化的时候被调用、每次路由切换之前被调用
    router.beforeEach(async (to, from, next) => {
        handleNProgress(to, true)
        const { user } = useStore()
        //设置页面标题
        if (to.meta && to.meta.title) {
            document.title = getPageTitle(i18n.global.t(to.meta.title))
        } else {
            document.title = getPageTitle()
        }

        const { whiteList } = defaultSettings
        if (whiteList.includes(to.path)) {
            // 在免登录白名单，直接进入
            next()
        } else if (getToken()) {
            if (to.path === '/login') {
                // 如果已经登录，但尝试访问登录页面，则重定向到首页
                next({ path: '/' })
            }
            if (user.roles.length > 0) {
                next()
            } else {
                await rolesAndPermissionsHandler(router, to, from, next)
            }
        } else {
            // 没有token也不在不处理的白名单就把请求重定向到登陆页
            //使用 encodeURIComponent 对 to.fullPath 进行编码，以确保URL中的特殊字符（如 ?, &, =, # 等）不会导致问题
            //to.fullPath包含请求时的参数
            next({ path: `/login?redirect=${encodeURIComponent(to.fullPath)}` })
        }
    })

    //全局后置路由守卫————初始化的时候被调用、每次路由切换之后被调用
    router.afterEach((to, from, failure) => {
        handleNProgress(to, false)
        if (failure) {
            handleNavigationFailure(to, from, failure)
        }
    })
}
